import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { InventoryHistory as InventoryHistoryEntity } from '@/entity/InventoryHistory';
import { DataSource, DeepPartial, Repository } from 'typeorm';
import { CommonService } from '../common/common.service';
import { CreateInventoryHistoryRequest } from './dto/request.dto';
import { Brand as BrandEntity } from '@/entity/Brand';
import { PaginationConfig } from '@/types';

@Injectable()
export class InventoryHistoryService extends CommonService<InventoryHistoryEntity> {
  constructor(
    @InjectRepository(InventoryHistoryEntity)
    private readonly inventoryHistoryRepository: Repository<InventoryHistoryEntity>,
    private dataSource: DataSource,
  ) {
    super(inventoryHistoryRepository);
  }

  async createInventoryHistory(
    toAddHistoryInfo: CreateInventoryHistoryRequest,
  ) {
    const { brandId, type, nub } = toAddHistoryInfo;
    // 开启事务
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    let resultSetId: number | null = null;
    try {
      // 开启事务
      await queryRunner.startTransaction();
      // 先更新，触发校验，如果brand不存在更新失败返回错误
      await queryRunner.manager
        .getRepository(BrandEntity)
        .createQueryBuilder()
        .update()
        .set({
          stock: () => {
            const isAdd = type === '1';
            return `IF(${isAdd}, stock + ${nub}, stock - ${nub})`;
          },
        })
        .where('id = :brandId', { brandId })
        .execute();
      // 创建历史记录
      const result = await queryRunner.manager
        .getRepository(InventoryHistoryEntity)
        .createQueryBuilder()
        .insert()
        .values([toAddHistoryInfo])
        .execute();
      // 创建的第一个记录id
      resultSetId = result.identifiers[0].id;
      // 结束事务
      await queryRunner.commitTransaction();
    } catch (error) {
      // 发生错误回滚
      await queryRunner.rollbackTransaction();
      throw error;
    }
    // 释放
    await queryRunner.release();
    return resultSetId;
  }

  async updateInventoryHistory(
    inventoryHistoryId: InventoryHistoryEntity['id'],
    toUpdateHistoryInfo: Partial<InventoryHistoryEntity>,
  ) {
    // 找到库存记录
    const inventoryHistoryEntity =
      await this.inventoryHistoryRepository.findOneBy({
        id: inventoryHistoryId,
      });
    if (!inventoryHistoryEntity) {
      throw '库存记录不存在';
    }
    // 开启事务
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    try {
      // 开启事务
      await queryRunner.startTransaction();
      // 创建历史记录
      await queryRunner.manager
        .getRepository(InventoryHistoryEntity)
        .createQueryBuilder()
        .update()
        .set(toUpdateHistoryInfo)
        .where('id = :inventoryHistoryId', { inventoryHistoryId })
        .execute();
      const lastCalcStock =
        inventoryHistoryEntity.nub * Number(inventoryHistoryEntity.type);
      const newCalcStock =
        toUpdateHistoryInfo.nub * Number(toUpdateHistoryInfo.type);
      // 判断品牌库存是否需要更新库存
      const toAddStock = newCalcStock - lastCalcStock;
      if (toAddStock) {
        await queryRunner.manager
          .getRepository(BrandEntity)
          .createQueryBuilder()
          .update()
          .set({
            stock: () => {
              return `stock + ${toAddStock}`;
            },
          })
          .where('id = :brandId', { brandId: inventoryHistoryEntity.brandId })
          .execute();
      }
      // 结束事务
      await queryRunner.commitTransaction();
    } catch (error) {
      // 发生错误回滚
      await queryRunner.rollbackTransaction();
      throw error;
    }
    // 释放
    await queryRunner.release();
  }

  // 删除记录
  async deleteInventoryHistory(
    inventoryHistoryId: InventoryHistoryEntity['id'],
  ) {
    // 找到库存记录
    const inventoryHistoryEntity =
      await this.inventoryHistoryRepository.findOneBy({
        id: inventoryHistoryId,
      });
    if (!inventoryHistoryEntity) {
      throw '库存记录不存在';
    }
    // 开启事务
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    try {
      // 开启事务
      await queryRunner.startTransaction();
      // 创建历史记录
      await queryRunner.manager
        .getRepository(InventoryHistoryEntity)
        .createQueryBuilder()
        .delete()
        .where('id = :inventoryHistoryId', { inventoryHistoryId })
        .execute();
      // 判断品牌库存是否需要更新库存
      const toSubtractStock =
        inventoryHistoryEntity.nub * Number(inventoryHistoryEntity.type);
      if (toSubtractStock) {
        await queryRunner.manager
          .getRepository(BrandEntity)
          .createQueryBuilder()
          .update()
          .set({
            stock: () => {
              return `stock - ${toSubtractStock}`;
            },
          })
          .where('id = :brandId', { brandId: inventoryHistoryEntity.brandId })
          .execute();
      }
      // 结束事务
      await queryRunner.commitTransaction();
    } catch (error) {
      // 发生错误回滚
      await queryRunner.rollbackTransaction();
      throw error;
    }
    // 释放
    await queryRunner.release();
  }

  async findAllAndCount(
    findOption: DeepPartial<InventoryHistoryEntity> & {
      createStartTime?: number;
      createEndTime?: number;
      sortField?: 'createTime';
      sortType?: 'DESC' | 'ASC';
    },
    pagination: PaginationConfig,
  ) {
    let sqlPromise = this.inventoryHistoryRepository
      .createQueryBuilder('inventory_history')
      .leftJoinAndSelect('inventory_history.brand', 'brand')
      .where('');
    if (findOption.brandId) {
      sqlPromise = sqlPromise.andWhere(
        'inventory_history.brand_id = :brandId',
        {
          brandId: findOption.brandId,
        },
      );
    }
    if (findOption.id) {
      sqlPromise = sqlPromise.andWhere('inventory_history.id = :id', {
        id: findOption.id,
      });
    }
    if (findOption.type) {
      sqlPromise = sqlPromise.andWhere('inventory_history.type = :type', {
        type: findOption.type,
      });
    }
    // 时间范围
    if (findOption.createStartTime && findOption.createEndTime) {
      sqlPromise = sqlPromise
        .andWhere(
          'unix_timestamp(inventory_history.create_time) >= :createStartTime',
          {
            createStartTime: findOption.createStartTime / 1000,
          },
        )
        .andWhere(
          'unix_timestamp(inventory_history.create_time) <= :createEndTime',
          {
            createEndTime: findOption.createEndTime / 1000,
          },
        );
    }
    // 排序
    if (findOption.sortField && findOption.sortType) {
      sqlPromise = sqlPromise.orderBy(
        `inventory_history.${findOption.sortField}`,
        findOption.sortType,
      );
    } else {
      sqlPromise = sqlPromise.orderBy('inventory_history.updateTime', 'DESC');
    }
    // 分页
    const [list, total] = await Promise.all([
      sqlPromise
        .skip(pagination.pageSize * (pagination.current - 1))
        .take(pagination.pageSize)
        .getMany(),
      sqlPromise.getCount(),
    ]);
    return {
      list,
      total,
    };
  }
}
